﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Web;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Net;


namespace MyLibrary.Tools
{
    public class CommonTools
    {
        #region 构造函数
        static CommonTools()
        {
        }
        #endregion

        #region 加解密的静态方法
        private static string EncryptBySHA1(string srcStr)
        {
            if (srcStr == String.Empty || srcStr == "") return String.Empty;

            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] srcByte = Encoding.Default.GetBytes(srcStr);
            byte[] encryptByte = sha1.ComputeHash(srcByte);

            StringBuilder sb = new StringBuilder();
            for (int lenght = 0; lenght < encryptByte.Length; lenght++)
                sb.AppendFormat("{0:X2}", encryptByte[lenght]);
            return sb.ToString();
        }

        private static string EncryptKey(string srcStr, string encryptKey)
        {
            encryptKey = EncryptBySHA1(encryptKey);

            int ctr = 0;
            string tmp = String.Empty;

            for (int length = 0; length < srcStr.Length; length++)
            {
                ctr = ctr == encryptKey.Length ? 0 : ctr;
                //在tmp字符串的末尾加上一位,内容为srcStr的第length位
                tmp += ((char)(srcStr[length] ^ encryptKey[ctr++])).ToString();
            }
            return tmp;
        }

        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="srcStr">要加密的字符串</param>
        /// <param name="key">KEY</param>
        /// <returns>加密后的字符串</returns>
        public static string Encrypt(string srcStr, string key)
        {
            string ikey = "logextraction=>dbconnection";
            string encryptKey = EncryptBySHA1(ikey);

            int ctr = 0;
            string tmp = String.Empty;

            for (int i = 0; i < srcStr.Length; i++)
            {
                ctr = ctr == encryptKey.Length ? 0 : ctr;
                tmp += encryptKey[ctr].ToString() + ((char)(srcStr[i] ^ encryptKey[ctr++])).ToString();
            }
            return Convert.ToBase64String(Encoding.Default.GetBytes(EncryptKey(tmp, key)));
        }

        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="encryptStr">要解密的字符</param>
        /// <param name="key">KEY</param>
        /// <returns>解密后的字符串</returns>
        public static string Decrypt(string encryptStr, string key)
        {
            encryptStr = EncryptKey(Encoding.Default.GetString(Convert.FromBase64String(encryptStr)), key);

            string tmp = String.Empty;
            for (int length = 0; length < encryptStr.Length; length++)
                tmp += ((char)(encryptStr[length] ^ encryptStr[++length])).ToString();
            return tmp;
        }
        #endregion

        #region 动态调用取得用户信息的WebService方法
        /// <summary>
        /// 动态编译WebService
        /// </summary>
        /// <param name="url">指向WebService的URL</param>
        /// <param name="nmSpace">编译使用的命名空间(默认值为"DyncWebService")该参数如设置为String.Empty则使用默认值</param>
        /// <param name="asmName">编译使用的Assembly名称</param>
        /// <param name="refAsm">编译所需使用的Reference Assembly 动态编译时已经载入 
        /// System.dll,System.XML.dlll,System.Web.Services.dll,System.Data.dll.如果不需要载入其他Assembly.该值为null</param>
        /// <param name="errors">编译过程中的错误信息,如果编译成功该数组全为空</param>
        /// <returns>编译结果(0=编译成功,1=编译失败)</returns>
        public static int DynamicCompileWebService(string url, string nmSpace, string asmName, string[] refAsm, ref List<string> errors)
        {
            if (url == "" || url == String.Empty) throw new ArgumentNullException("url");
            if (asmName == "" || asmName == String.Empty) throw new ArgumentNullException("asmName");

            try
            {
                //下载WSDL信息
                WebClient web = new WebClient();
                Stream stream = web.OpenRead(url + "?WSDL");

                //创建并格式化WSDL文档
                ServiceDescription description = ServiceDescription.Read(stream);

                //创建客户端代理类
                ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
                importer.ProtocolName = "Soap";
                importer.Style = ServiceDescriptionImportStyle.Client;
                importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
                importer.AddServiceDescription(description, null, null);

                //使用CodeDom编译客户端代理类
                CodeNamespace nmspace = new CodeNamespace();
                if (nmSpace != String.Empty)
                    nmspace.Name = nmSpace;
                else
                    nmspace.Name = "DyncWebService";

                CodeCompileUnit unit = new CodeCompileUnit();
                unit.Namespaces.Add(nmspace);

                ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
                CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

                CompilerParameters parameter = new CompilerParameters();
                parameter.GenerateExecutable = false;
                parameter.OutputAssembly = asmName;
                parameter.ReferencedAssemblies.Add("System.dll");
                parameter.ReferencedAssemblies.Add("System.XML.dll");
                parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
                parameter.ReferencedAssemblies.Add("System.Data.dll");
                if (refAsm != null)
                {
                    for (int i = 0; i < refAsm.Length; i++)
                        parameter.ReferencedAssemblies.Add(refAsm[i]);
                }

                CompilerResults result = provider.CompileAssemblyFromDom(parameter, unit);
                if (result.Errors.HasErrors)
                {
                    foreach (CompilerError error in result.Errors)
                        errors.Add(error.ToString());
                    return 1;
                }

                return 0;
            }
            catch (WebException wex)
            {
                Console.WriteLine(wex.Message);
                return 1;
            }
            catch (NotImplementedException niex)
            {
                Console.WriteLine(niex.Message);
                return 1;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return 1;
            }
        }
        #endregion

        #region 读取或设置程序执行配置文件的方法
        /// <summary>
        /// 读取指定XPath的节点集
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <returns>读取的值</returns>
        public static Dictionary<string, string> GetConfigSections2(string xpath, string xmlfile)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            //读取复数的键值
            XmlNode nodes = document.SelectSingleNode(xpath);
            if (nodes != null)
            {
                Dictionary<string, string> xmlValues = new Dictionary<string, string>();
                foreach (XmlNode node in nodes.ChildNodes)
                    xmlValues.Add(node.Name, node.InnerText);
                return xmlValues;
            }
            return null;
        }
        /// <summary>
        /// 读取指定节点的值[复数]
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <returns>读取的值</returns>
        public static Dictionary<string,string> GetConfigSections2(string xpath,string attrKey,string xmlfile)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            //读取复数的键值
            XmlNodeList nodes = document.SelectNodes(xpath);
            if (nodes.Count != 0)
            {
                Dictionary<string, string> xmlValues = new Dictionary<string,string>();
                foreach (XmlNode node in nodes)
                {
                    if (!xmlValues.ContainsKey(node.Attributes[attrKey].Value))
                        xmlValues.Add(node.Attributes[attrKey].Value, Decrypt(node.InnerText, xpath));
                }
                return xmlValues;
            }
            return null;
        }
        /// <summary>
        /// 读取指定节点的值
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <returns>读取的值</returns>
        public static string GetConfigSection(string xpath,string xmlfile)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            //以该键值的XMLPath为Key进行解密,所有XMLPath值不可变
            XmlNode node = document.SelectSingleNode(xpath);
            if (node != null)
                return Decrypt(node.InnerText, xpath);
            return String.Empty;
        }
        /// <summary>
        /// 读取指定节点的值,不进行解密
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <returns>读取的值</returns>
        public static string GetConfigSectionNoEncrypt(string xpath, string xmlfile)
        {
            XmlNode node = GetConfigNode(xpath, xmlfile);
            if (node == null) return String.Empty;
            return node.InnerText;
        }

        /// <summary>
        /// 读取指定的节点,返回原始节点对象
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <returns>读取到的节点</returns>
        public static XmlNode GetConfigNode(string xpath, string xmlfile)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            XmlNode node = null;
            node = document.SelectSingleNode(xpath);
            if (node != null)
                return node;
            return null;
        }

        /// <summary>
        /// 设置指定节点的值
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <param name="value">设置的值</param>
        public static void SetConfigSection(string xpath, string xmlfile, string value)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            //以该键值的XMLPath为Key进行加密,所有XMLPath值不可变
            XmlNode node = document.SelectSingleNode(xpath);
            if (node != null)
                //node.InnerText = value;
                node.InnerText = Encrypt(value, xpath);
            document.Save(xmlfile);
        }

        /// <summary>
        /// 设置指定节点的值,不进行加密
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <param name="value">设置的值</param>
        public static void SetConfigSectionNoEncrypt(string xpath, string xmlfile, string value)
        {
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            //以该键值的XMLPath为Key进行加密,所有XMLPath值不可变
            XmlNode node = document.SelectSingleNode(xpath);
            if (node != null)
                node.InnerText = value;
            document.Save(xmlfile);
        }

        /// <summary>
        /// 设置Xml节点的值
        /// </summary>
        /// <param name="xpath">节点的XPath</param>
        /// <param name="xmlfile">XML文件的路径</param>
        /// <param name="value">设置的值</param>
        /// <param name="attributesName">属性名</param>
        /// <param name="attributesValue">属性值</param>
        public static void SetConfigNode(string xpath, string xmlfile, string value, string[] attributesName,params string[] attributesValue)
        {
            if (attributesName.Length != attributesValue.Length) throw new ArgumentException("要设置属性名称和值的个数无法对应");
            XmlDocument document = new XmlDocument();
            document.Load(xmlfile);

            XmlNode node = document.SelectSingleNode(xpath);
            if(!String.IsNullOrEmpty(value))
                node.InnerText = value;
            for (int i = 0; i < attributesName.Length; i++)
            {
                if (node.Attributes[attributesName[i]] != null)
                    node.Attributes[attributesName[i]].Value = attributesValue[i];
            }
            document.Save(xmlfile);
        }
        #endregion

        #region 写文本日志
        public static void Write(string text, string path)
        {
            string fullContent;
            fullContent = String.Format("[{0}] {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), text);

            try
            {
                if (!File.Exists(path))
                {
                    using (StreamWriter create = File.CreateText(path))
                    {
                        create.WriteLine(fullContent);
                    }
                }
                else
                {
                    using (StreamWriter append = File.AppendText(path))
                    {
                        append.WriteLine(fullContent);
                    }
                }
            }
            catch
            {
            }
            finally
            {
                
            }
        }
        #endregion

        #region IP地址与Int类型直接的转换
        /// <summary>
        /// 检查传入的数据是否为IP
        /// </summary>
        /// <param name="IP"></param>
        /// <returns></returns>
        private static bool CheckIPAddress(string IP)
        {
            string pattern = @"(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))";
            Regex regex = new Regex(pattern);
            if (regex.Match(IP).Success)
                return true;
            else
                return false;
        }
        /// <summary>
        /// 将IP转换成为INT
        /// </summary>
        /// <param name="ip">IP地址</param>
        /// <returns>INT类型的IP</returns>
        public static long IPToInt(string ip)
        {
            if (!CheckIPAddress(ip)) return -1;

            if (ip.Split('.').Length == 3)
                ip = ip + ".0";
            string[] strArray = ip.Split('.');
            long num2 = ((long.Parse(strArray[0]) * 0x100L) * 0x100L) * 0x100L;
            long num3 = (long.Parse(strArray[1]) * 0x100L) * 0x100L;
            long num4 = long.Parse(strArray[2]) * 0x100L;
            long num5 = long.Parse(strArray[3]);
            return (((num2 + num3) + num4) + num5);
        }

        /// <summary>
        /// 将INT转换为IP地址
        /// </summary>
        /// <param name="ipint">INT形式的IP地址</param>
        /// <returns>IP地址</returns>
        public static string IntToIP(long ipint)
        {
            long num = (long)((ipint & 0xff000000L) >> 0x18);
            if (num < 0L)
                num += 0x100L;

            long num2 = (ipint & 0xff0000L) >> 0x10;
            if (num2 < 0L)
                num2 += 0x100L;

            long num3 = (ipint & 0xff00L) >> 0x8;
            if (num3 < 0L)
                num3 += 0x100L;

            long num4 = ipint & 0xffL;
            if (num4 < 0L)
                num4 += 0x100L;

            return (num.ToString() + "." + num2.ToString() + "." + num3.ToString() + "." + num4.ToString());
        }
        #endregion
    }
}
